﻿using DTcms.Core.Common.Emum;
using DTcms.Core.Common.Extensions;
using DTcms.Core.Common.Helper;
using DTcms.Core.DBFactory.Database;
using DTcms.Core.IServices;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace DTcms.Core.Services
{
    public class BaseService : IBaseService
    {
        protected DbContext _context { get; set; } //DbContext对象
        protected IDbContextFactory _contextFactory { get; private set; } //DbContext工厂对象

        /// <summary>
        /// 构造函数
        /// 依赖注入数据库工厂
        /// </summary>
        public BaseService(IDbContextFactory contextFactory)
        {
            _contextFactory = contextFactory; //依赖注入工厂
        }

        /// <summary>
        /// 检查记录是否存在
        /// </summary>
        public virtual async Task<bool> ExistsAsync<T>(Expression<Func<T, bool>> funcWhere, WriteRoRead writeAndRead = WriteRoRead.Read) where T : class
        {
            _context = _contextFactory.CreateContext(writeAndRead);
            return await _context.Set<T>().FirstOrDefaultAsync(funcWhere) != null;
        }

        /// <summary>
        /// 取得最新一条记录
        /// </summary>
        public virtual async Task<T> QueryAsync<T>(WriteRoRead writeAndRead = WriteRoRead.Read) where T : class
        {
            _context = _contextFactory.CreateContext(writeAndRead);
            return await _context.Set<T>().FirstOrDefaultAsync();
        }

        /// <summary>
        /// 查询一条记录
        /// </summary>
        public virtual async Task<T> QueryAsync<T>(Expression<Func<T, bool>> funcWhere, WriteRoRead writeAndRead = WriteRoRead.Read) where T : class
        {
            _context = _contextFactory.CreateContext(writeAndRead);
            return await _context.Set<T>().FirstOrDefaultAsync(funcWhere);
        }

        /// <summary>
        /// 查询返回指定数据列表
        /// </summary>
        public virtual async Task<IEnumerable<T>> QueryListAsync<T>(int top, Expression<Func<T, bool>> funcWhere,
            WriteRoRead writeAndRead = WriteRoRead.Read) where T : class
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库

            var result = _context.Set<T>().Where<T>(funcWhere);
            if (top > 0) result = result.Take(top);
            return await result.ToListAsync();
        }

        /// <summary>
        /// 返回指定数量数据，带排序
        /// </summary>
        /// <param name="top">显示条数</param>
        /// <param name="funcWhere">查询表达式</param>
        /// <param name="orderBy">排序</param>
        public virtual async Task<IEnumerable<T>> QueryListAsync<T>(int top, Expression<Func<T, bool>> funcWhere, string orderBy,
            WriteRoRead writeAndRead = WriteRoRead.Read) where T : class
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库

            var result = _context.Set<T>().Where<T>(funcWhere);//条件筛选
            result = LinqExtensions.OrderByBatch<T>(result, orderBy);//调用Linq扩展类进行排序
            if (top > 0) result = result.Take(top);//等于0显示所有数据
            return await result.ToListAsync();
        }

        /// <summary>
        /// 返回分页记录，带排序
        /// </summary>
        /// <param name="pageSize">每页数量</param>
        /// <param name="pageIndex">当前页码</param>
        /// <param name="totalCount">总记录数</param>
        /// <param name="funcWhere">查询表达式</param>
        /// <param name="orderBy">排序</param>
        public virtual IQueryable<T> QueryPage<T>(int pageSize,int pageIndex, out int totalCount,Expression<Func<T, bool>> funcWhere,
            string orderBy, WriteRoRead writeAndRead = WriteRoRead.Read) where T : class
        {
            if (pageIndex < 1) pageIndex = 1;
            if (pageSize < 1) pageSize = 10;

            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            IQueryable<T> result = _context.Set<T>().Where(funcWhere);//条件筛选
            result = LinqExtensions.OrderByBatch<T>(result, orderBy);//调用Linq扩展类排序
            totalCount = result.Count();//取得总记录数
            return result.Skip((pageIndex - 1) * pageSize).Take(pageSize);
        }

        public virtual async Task<PaginationList<T>> QueryPageAsync<T>(int pageSize, int pageIndex, Expression<Func<T, bool>> funcWhere,
            string orderBy, WriteRoRead writeAndRead = WriteRoRead.Read) where T : class
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            IQueryable<T> result = _context.Set<T>().Where(funcWhere);//条件筛选
            result = LinqExtensions.OrderByBatch<T>(result, orderBy);//调用Linq扩展类排序
            return await PaginationList<T>.CreateAsync(pageIndex, pageSize, result);
        }

        /// <summary>
        /// 新增一条数据
        /// </summary>
        public virtual async Task<T> AddAsync<T>(T t, WriteRoRead writeAndRead = WriteRoRead.Write) where T : class
        {
            if (writeAndRead == WriteRoRead.Read)
            {
                throw new ResponseException("增删改操作不能指向从库！");
            }
            _context = _contextFactory.CreateContext(writeAndRead);
            await _context.Set<T>().AddAsync(t);
            await this.SaveAsync();
            return t;
        }

        /// <summary>
        /// 新增多条数据(带事务)
        /// </summary>
        public virtual async Task<IEnumerable<T>> AddAsync<T>(IEnumerable<T> tList, WriteRoRead writeAndRead = WriteRoRead.Write) where T : class
        {
            _context = _contextFactory.CreateContext(writeAndRead);
            await _context.Set<T>().AddRangeAsync(tList);
            await this.SaveAsync();
            return tList;
        }

        /// <summary>
        /// 修改一条数据
        /// </summary>
        public virtual async Task<bool> UpdateAsync<T>(T t, WriteRoRead writeAndRead = WriteRoRead.Write) where T : class
        {
            _context = _contextFactory.CreateContext(writeAndRead);
            if (t == null)
            {
                throw new ResponseException("数据不能为NULL！");
            }
            _context.Set<T>().Attach(t);
            _context.Entry<T>(t).State = EntityState.Modified;
            return await this.SaveAsync();
        }

        /// <summary>
        /// 修改多条数据(带事务)
        /// </summary>
        public virtual async Task<bool> UpdateAsync<T>(IEnumerable<T> tList, WriteRoRead writeAndRead = WriteRoRead.Write) where T : class
        {
            _context = _contextFactory.CreateContext(writeAndRead);
            foreach (var t in tList)
            {
                _context.Set<T>().Attach(t);
                _context.Entry<T>(t).State = EntityState.Modified;
            }
            return await this.SaveAsync();
        }

        /// <summary>
        /// 根据条件删除数据
        /// </summary>
        public virtual async Task<bool> DeleteAsync<T>(Expression<Func<T, bool>> funcWhere, WriteRoRead writeAndRead = WriteRoRead.Write) where T : class
        {
            _context = _contextFactory.CreateContext(writeAndRead);
            IEnumerable<T> tList = await _context.Set<T>().Where(funcWhere).ToListAsync();
            if (tList == null)
            {
                return false;
            }
            foreach (var t in tList)
            {
                _context.Set<T>().Attach(t);
            }
            _context.Set<T>().RemoveRange(tList);
            return await this.SaveAsync();
        }

        /// <summary>
        /// 根据实体删除一条数据
        /// </summary>
        public virtual async Task<bool> DeleteAsync<T>(T t, WriteRoRead writeAndRead = WriteRoRead.Write) where T : class
        {
            _context = _contextFactory.CreateContext(writeAndRead);
            if (t == null)
            {
                throw new ResponseException("数据不存在或已删除！");
            }
            _context.Set<T>().Attach(t);
            _context.Set<T>().Remove(t);
            return await this.SaveAsync();
        }

        /// <summary>
        /// 删除多条数据(带事务)
        /// </summary>
        public virtual async Task<bool> DeleteAsync<T>(IEnumerable<T> tList, WriteRoRead writeAndRead = WriteRoRead.Write) where T : class
        {
            _context = _contextFactory.CreateContext(writeAndRead);
            foreach(var t in tList)
            {
                _context.Set<T>().Attach(t);
            }
            _context.Set<T>().RemoveRange(tList);
            return await this.SaveAsync();
        }

        /// <summary>
        /// 保存数据(异步为了保证事务)
        /// </summary>
        public async Task<bool> SaveAsync()
        {
            return (await _context.SaveChangesAsync() >= 0);
        }

        public virtual void Dispose()
        {
            if (_context != null)
            {
                _context.Dispose();
            }
        }
    }
}
